package com.zx.notification.consumer.service.impl;

import com.zx.core.wrapper.ObjectWrapper;
import com.zx.notification.common.dao.NotificationPushTasksMapper;
import com.zx.notification.common.enums.ChannelTypeEnum;
import com.zx.notification.common.enums.PushStatusEnum;
import com.zx.notification.common.model.NotificationPushTasks;
import com.zx.notification.consumer.components.ThirdPartyNotificationComponent;
import com.zx.notification.consumer.service.IMessageProcessService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.function.BiFunction;

/**
 * 消息处理服务实现类
 * 负责处理各种渠道的消息，包括站内信、WebSocket、短信、邮件等
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MessageProcessServiceImpl implements IMessageProcessService {

    private final ThirdPartyNotificationComponent thirdPartyNotificationComponent;
    private final NotificationPushTasksMapper notificationPushTasksMapper;

    /**
     * 更新任务状态
     *
     * @param taskId        任务ID
     * @param status        状态
     * @param sentTime      发送时间
     * @param errorMsg      错误信息
     * @param externalMsgId 外部消息ID
     */
    private void updateTaskStatus(String taskId, PushStatusEnum status, LocalDateTime sentTime, String errorMsg, String externalMsgId) {
        try {
            NotificationPushTasks task = new NotificationPushTasks();
            task.setId(taskId);
            task.setStatus(status.getCode());
            task.setUpdateTime(LocalDateTime.now());

            // 只有在成功时才设置发送时间
            if (sentTime != null) {
                task.setSentTime(sentTime);
            }

            // 设置外部消息ID
            if (externalMsgId != null && !externalMsgId.isEmpty()) {
                task.setExternalMsgId(externalMsgId);
            }

            // 设置错误信息
            if (errorMsg != null && !errorMsg.isEmpty()) {
                task.setErrorMsg(errorMsg);
                // 增加重试次数
                NotificationPushTasks existingTask = notificationPushTasksMapper.selectByPrimaryKey(taskId);
                if (existingTask != null) {
                    task.setRetryCount(existingTask.getRetryCount() + 1);
                }
            }

            notificationPushTasksMapper.updateByPrimaryKeySelective(task);
        } catch (Exception e) {
            log.error("更新任务状态失败: 任务ID={}, 状态={}", taskId, status, e);
        }
    }

    /**
     * 处理消息的通用方法
     *
     * @param notificationId 通知ID
     * @param title          消息标题
     * @param content        消息内容
     * @param userId         用户ID
     * @param taskId         任务ID
     * @param channelType    渠道类型
     * @param messageSender  消息发送函数
     */
    private void processMessage(String notificationId,
                                String title,
                                String content,
                                String userId,
                                String taskId,
                                String channelType,
                                BiFunction<String, String, ObjectWrapper<String>> messageSender) {
        // 更新任务状态为发送中
        updateTaskStatus(taskId, PushStatusEnum.SENDING, null, null, null);

        try {
            log.info("开始处理{}消息: 通知ID={}, 用户ID={}", channelType, notificationId, userId);

            // 发送消息
            String firstParam = null;
            String secondParam;

            // 根据不同渠道类型处理参数
            if (ChannelTypeEnum.INBOX.getCode().equals(channelType)) {
                // 站内信需要用户ID和标题
                firstParam = userId;
                secondParam = title;
            } else if (ChannelTypeEnum.WEBSOCKET.getCode().equals(channelType)) {
                // WebSocket需要内容，但不需要用户ID
                secondParam = content;
            } else if (ChannelTypeEnum.SMS.getCode().equals(channelType)) {
                // 短信需要用户ID和内容
                firstParam = userId;
                secondParam = content;
            } else if (ChannelTypeEnum.EMAIL.getCode().equals(channelType)) {
                // 邮件需要用户ID和内容
                firstParam = userId;
                secondParam = content;
            } else if (ChannelTypeEnum.APP_PUSH.getCode().equals(channelType)) {
                // APP推送需要用户ID和内容
                firstParam = userId;
                secondParam = content;
            } else if (ChannelTypeEnum.WECHAT.getCode().equals(channelType)) {
                // 微信需要用户ID和内容
                firstParam = userId;
                secondParam = content;
            } else {
                // 默认处理：大多数情况需要用户ID和内容
                firstParam = userId;
                secondParam = content;
            }

            ObjectWrapper<String> result = messageSender.apply(firstParam, secondParam);

            if (!result.verifyFail()) {
                // 更新任务状态为成功，并设置发送时间
                updateTaskStatus(taskId, PushStatusEnum.SUCCESS, LocalDateTime.now(), null, result.getData());
                log.info("{}消息处理成功: 通知ID={}, 用户ID={}", channelType, notificationId, userId);
            } else {
                // 更新任务状态为失败
                updateTaskStatus(taskId, PushStatusEnum.FAILED, null, result.getMsg(), null);
                log.error("处理{}消息失败: 通知ID={}, 用户ID={}, 错误信息={}", channelType, notificationId, userId, result.getMsg());
            }
        } catch (Exception e) {
            log.error("处理{}消息异常: 通知ID={}, 用户ID={}", channelType, notificationId, userId, e);
            // 更新任务状态为失败
            updateTaskStatus(taskId, PushStatusEnum.FAILED, null, e.getMessage(), null);
        }
    }

    /**
     * 处理站内信消息
     * 站内信直接写入数据库，所有实例均可访问，因此不需要跨实例转发机制
     *
     * @param notificationId 通知ID
     * @param title          消息标题
     * @param content        消息内容
     * @param userId         用户ID
     * @param taskId         任务ID
     */
    @Override
    public void processInboxMessage(String notificationId, String title, String content, String userId, String taskId) {
        processMessage(notificationId, title, content, userId, taskId, ChannelTypeEnum.INBOX.getCode(),
                (u, c) -> thirdPartyNotificationComponent.sendInboxMessage(notificationId, title, content, userId));
    }

    /**
     * 处理WebSocket消息
     *
     * @param notificationId 通知ID
     * @param title          消息标题
     * @param content        消息内容
     * @param userId         用户ID
     * @param taskId         任务ID
     */
    @Override
    public void processWebsocketMessage(String notificationId, String title, String content, String userId, String taskId) {
        processMessage(notificationId, title, content, userId, taskId, ChannelTypeEnum.WEBSOCKET.getCode(),
                (sessionId, c) -> thirdPartyNotificationComponent.sendWebSocketMessage(sessionId, content));
    }

    /**
     * 处理短信消息
     * 由于没有短信环境，暂时使用TODO处理
     *
     * @param notificationId 通知ID
     * @param content        消息内容
     * @param userId         用户ID
     * @param taskId         任务ID
     */
    @Override
    public void processSmsMessage(String notificationId, String content, String userId, String taskId) {
        processMessage(notificationId, null, content, userId, taskId, ChannelTypeEnum.SMS.getCode(),
                thirdPartyNotificationComponent::sendSms);
    }

    /**
     * 处理邮件消息
     *
     * @param notificationId 通知ID
     * @param content        消息内容
     * @param userId         用户ID
     * @param taskId         任务ID
     */
    @Override
    public void processEmailMessage(String notificationId, String content, String userId, String taskId) {
        processMessage(notificationId, null, content, userId, taskId, ChannelTypeEnum.EMAIL.getCode(),
                thirdPartyNotificationComponent::sendEmail);
    }

    /**
     * 处理APP推送消息
     * 由于没有APP推送环境，暂时使用TODO处理
     *
     * @param notificationId 通知ID
     * @param content        消息内容
     * @param userId         用户ID
     * @param taskId         任务ID
     */
    @Override
    public void processAppPushMessage(String notificationId, String content, String userId, String taskId) {
        processMessage(notificationId, null, content, userId, taskId, ChannelTypeEnum.APP_PUSH.getCode(),
                thirdPartyNotificationComponent::sendAppPush);
    }

    /**
     * 处理微信消息
     * 由于没有微信环境，暂时使用TODO处理
     *
     * @param notificationId 通知ID
     * @param content        消息内容
     * @param userId         用户ID
     * @param taskId         任务ID
     */
    @Override
    public void processWechatMessage(String notificationId, String content, String userId, String taskId) {
        processMessage(notificationId, null, content, userId, taskId, ChannelTypeEnum.WECHAT.getCode(),
                thirdPartyNotificationComponent::sendWechatMessage);
    }
}